import java.io.BufferedReader
import java.io.File
import java.io.InputStreamReader
import java.time.LocalDateTime
import java.util.concurrent.TimeUnit
import kotlin.system.exitProcess

//
//
// common functions: start
//
//
fun envCheck() {
    try {
        assert(true == false)
        println("assert disabled, can not go on")
        exitProcess(1)
    } catch (e: AssertionError) {
    }
}

fun Run(inCmd: String, inWorkdir: String? = null) {
    Run(inCmd.split(" "), inWorkdir)
}

fun Run(inCmd: List<String>, inWorkdir: String? = null) {
    println("Run: $inCmd")
    val pb: ProcessBuilder = ProcessBuilder(inCmd)
            .directory(File(inWorkdir ?: "."))
            .redirectErrorStream(true)
    val p = pb.start()
    val reader = BufferedReader(InputStreamReader(p.inputStream))
    while (true) {
        val line = reader.readLine() ?: break
        println(line)
    }
    p.waitFor()
    if (0 != p.exitValue()) {
        throw RuntimeException()
    }
}

fun CheckOutput(inCmd: String, inWorkdir: String? = null): List<String> {
    return CheckOutput(inCmd.split(" "), inWorkdir)
}

fun CheckOutput(inCmd: List<String>, inWorkdir: String? = null): List<String> {
    println("Run: $inCmd")
    val ret = mutableListOf<String>()
    val pb: ProcessBuilder = ProcessBuilder(inCmd)
            .directory(File(inWorkdir ?: "."))
            .redirectErrorStream(true)
    val p = pb.start()
    val reader = BufferedReader(InputStreamReader(p.inputStream))
    while (true) {
        val line = reader.readLine() ?: break
        ret.add(line)
    }
    p.waitFor()
    if (0 != p.exitValue()) {
        throw RuntimeException()
    }
    return ret
}
//
//
// common functions: end
//
//



//
//
// ADB functions: start
//
//
fun adbShell(inCmd: String, deviceSN: String) {
    Run("adb -s $deviceSN shell $inCmd")
}

fun adbShell2(inCmd: String, deviceSN: String) {
    Run(listOf("adb", "-s", deviceSN, "shell", inCmd))
}


fun isDeviceOnline(deviceSN: String): Boolean {
    var ret = false
    CheckOutput("adb devices").forEach {
        if (it.contains(deviceSN)) {
            ret = true
        }
    }
    return ret
}

fun isDeviceBootComplete(deviceSN: String): Boolean {
    val bootComp = CheckOutput("adb -s $deviceSN shell getprop sys.boot_completed")
    if (bootComp.size == 1 && bootComp[0] == "1") {
        return true
    }
    return false
}

fun enableChatty(deviceSN: String) {
    adbShell("echo N > /sys/module/printk/parameters/console_suspend", deviceSN)
    adbShell("echo 8 > /proc/sys/kernel/printk", deviceSN)
}

fun checkDisplayStatus(): Boolean {
    val ret = CheckOutput("adb shell dumpsys power").filter { it.contains("Display Power") }
    assert(ret.size == 1)
    assert(ret[0].matches(".*(ON|OFF)".toRegex())) { "Unknown display power status: " + ret[0] }
    if (ret[0].contains("=ON")) {
        println("Display ON")
        return true
    }
    if (ret[0].contains("=OFF")) {
        println("Display OFF")
        return false
    }
    assert(false)
    return false
}

//
//
// ADB functions: start
//
//

var theSN = "X"
envCheck()
if (args.size != 1) {
    println("usage: prog <deviceId>")
    exitProcess(1)
} else {
    theSN = args[0]
}

fun sz2String(size: Long): String? {
    val kilo = 1024L
    val mega = kilo * kilo
    val giga = mega * kilo
    val tera = giga * kilo
    var s = ""
    val kb: Double = size.toDouble() / kilo
    val mb: Double = kb / kilo
    val gb: Double = mb / kilo
    val tb: Double = gb / kilo
    if (size < kilo) {
        s = "$size Bytes"
    } else if (size in kilo until mega) {
        s = String.format("%.2f", kb) + " KB"
    } else if (size in mega until giga) {
        s = String.format("%.2f", mb) + " MB"
    } else if (size in giga until tera) {
        s = String.format("%.2f", gb) + " GB"
    } else if (size >= tera) {
        s = String.format("%.2f", tb) + " TB"
    }
    return s
}

data class Partition(
    var name: String = "",
    var sz: Long = 0,
)

fun getPartitionInfo(partName: String) {
    val sz = CheckOutput("adb -s $theSN shell blockdev --getsize64 /dev/block/by-name/$partName").get(0).trim().toLong()
    val blockDev = CheckOutput("adb -s $theSN shell readlink /dev/block/by-name/$partName").get(0).trim()
    println("Part       : $partName $sz")
    println("Part Size  : $partName " + sz2String(sz))
    println("Part Device: $partName " + blockDev)
}

val parts = CheckOutput("adb -s $theSN shell ls /dev/block/by-name")
parts.forEach {
    getPartitionInfo(it)
}

